package com.example.dw.util.formulademo;


import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class FormulaParser {

    private static final Map<String, java.lang.reflect.Method> methodRegistry = new ConcurrentHashMap<>();

    public static void main(String[] args) throws Exception {
        try {
            registerMethods(MathOperations.class);
            registerMethods(StringOperations.class);
            registerMethods(LogicalOperations.class);
        } catch (Exception e) {
            throw new RuntimeException("Failed to register builtin methods", e);
        }
        Map<String,Object> map = new HashMap<>();
        map.put("key1",100);
        map.put("key2",300);
        // 测试各种公式
        Object val=executeFormula("@add(@multiply(2, @add(4,5)), @multiply(4, 500))");
        System.out.println("val "+val);
        Object val2=executeFormula("@add(10, 20)");
        System.out.println("val2 "+val2);
        Object val3=executeFormula("@multiply(5, @add(key1,key2))",map);
        System.out.println("val3 "+val3);
        Object val4=executeFormula(" @add(10 , 20) ");
        System.out.println("val4 "+val4);
        Object val5=executeFormulaScript("@add",6,7);
        System.out.println(val5);
        Object val6=executeFormulaScript("@helloword");
        System.out.println(val6);
    }

    private static Object executeFormulaScript(String formula,Object ... args) throws Exception {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(formula);
        stringBuilder.append("(");
        Map<String,Object> map=null;
        if(args!=null && args.length>0) {
            map = new HashMap<>();
            for(int i=0;i<args.length;i++) {
                String key="key"+i;
                map.put(key,args[i]);
                stringBuilder.append(key).append(",");
            }
        }
        if(args!=null && args.length>0){
            stringBuilder.deleteCharAt(stringBuilder.length()-1);
        }
        stringBuilder.append(")");
        return executeFormula(stringBuilder.toString(),map);
    }

    private static Object executeFormula(String formula) {
        if(formula!=null){
            formula=formula.trim();
        }
        return executeFormula(formula,null);
    }

    private static Object executeFormula(String formula,Map<String,Object> map) {
        try {
            FormulaParser.MethodInfo info = FormulaParser.extractMethod(formula);
            java.lang.reflect.Method method = methodRegistry.get(info.getMethodName().toLowerCase());
            if(method != null) {
                // System.out.println(method.getName());
                List<Object> objects = new LinkedList<>();
                // 打印每个参数的详细信息
                for (int i = 0; i < info.getParameters().size(); i++) {
                    String param = info.getParameters().get(i);
                    Object paramObj=param;
                    //参数包含嵌套公式
                    if(isNestedFormula(param)){
                        paramObj=executeFormula(param,map);
                    }
                    //当上下文参数不为空
                    if(map!=null && map.containsKey(param)){
                        paramObj=map.get(param);
                    }
                    //转换参数
                    Object object=convertParameters(method,paramObj,i);
                    objects.add(object);
                }
                // 获取方法所在类的实例
                Object instance = method.getDeclaringClass().newInstance();
                Object result = method.invoke(instance, objects.toArray());
                return result;
            }
        } catch (Exception e) {
            System.out.println("错误: " + e.getMessage());
        }
        return null;
    }


    private static Object convertParameters(java.lang.reflect.Method method,Object object,Integer index){
        Class<?>[] paramTypes = method.getParameterTypes();
        Class<?> cls = paramTypes[index];
        return  convertParameter(object,cls);
    }


    /**
     * 单个参数类型转换
     */
    private static Object convertParameter(Object value, Class<?> targetType) {
        if (value == null) {
            return getDefaultValue(targetType);
        }

        // 如果已经是目标类型，直接返回
        if (targetType.isInstance(value)) {
            return value;
        }

        // 类型转换
        if (targetType == String.class) {
            return String.valueOf(value);
        }

        // 数字类型转换
        if (targetType == int.class || targetType == Integer.class) {
            return toInteger(value);
        } else if (targetType == long.class || targetType == Long.class) {
            return toLong(value);
        } else if (targetType == double.class || targetType == Double.class) {
            return toDouble(value);
        } else if (targetType == float.class || targetType == Float.class) {
            return toFloat(value);
        } else if (targetType == boolean.class || targetType == Boolean.class) {
            return toBoolean(value);
        }

        throw new IllegalArgumentException(
                String.format("Cannot convert value '%s' from %s to %s",
                        value, value.getClass().getSimpleName(), targetType.getSimpleName()));
    }

    private static Object getDefaultValue(Class<?> type) {
        if (type == boolean.class) return false;
        if (type == byte.class) return (byte) 0;
        if (type == char.class) return '\0';
        if (type == short.class) return (short) 0;
        if (type == int.class) return 0;
        if (type == long.class) return 0L;
        if (type == float.class) return 0.0f;
        if (type == double.class) return 0.0;
        return null;
    }

    private static Integer toInteger(Object value) {
        if (value instanceof Number) {
            return ((Number) value).intValue();
        } else if (value instanceof String) {
            return Integer.parseInt((String) value);
        } else if (value instanceof Boolean) {
            return (Boolean) value ? 1 : 0;
        }
        throw new IllegalArgumentException("Cannot convert to Integer: " + value);
    }

    private static Long toLong(Object value) {
        if (value instanceof Number) {
            return ((Number) value).longValue();
        } else if (value instanceof String) {
            return Long.parseLong((String) value);
        } else if (value instanceof Boolean) {
            return (Boolean) value ? 1L : 0L;
        }
        throw new IllegalArgumentException("Cannot convert to Long: " + value);
    }

    private static Double toDouble(Object value) {
        if (value instanceof Number) {
            return ((Number) value).doubleValue();
        } else if (value instanceof String) {
            return Double.parseDouble((String) value);
        } else if (value instanceof Boolean) {
            return (Boolean) value ? 1.0 : 0.0;
        }
        throw new IllegalArgumentException("Cannot convert to Double: " + value);
    }

    private static Float toFloat(Object value) {
        if (value instanceof Number) {
            return ((Number) value).floatValue();
        } else if (value instanceof String) {
            return Float.parseFloat((String) value);
        } else if (value instanceof Boolean) {
            return (Boolean) value ? 1.0f : 0.0f;
        }
        throw new IllegalArgumentException("Cannot convert to Float: " + value);
    }

    private static Boolean toBoolean(Object value) {
        if (value instanceof Boolean) {
            return (Boolean) value;
        } else if (value instanceof String) {
            return Boolean.parseBoolean((String) value);
        } else if (value instanceof Number) {
            return ((Number) value).doubleValue() != 0;
        }
        throw new IllegalArgumentException("Cannot convert to Boolean: " + value);
    }

    /**
     * 注册自定义方法类
     */
    public static void registerMethods(Class<?> clazz) {
        for (java.lang.reflect.Method method : clazz.getDeclaredMethods()) {
            Method annotation = method.getAnnotation(Method.class);
            if (annotation != null) {
                String methodName = annotation.name();
                methodRegistry.put(methodName.toLowerCase(), method);
               // System.out.println("注册方法: " + methodName);
            }
        }
    }



    private static boolean isNestedFormula(String param) {
        return param.startsWith("@") && param.contains("(") && param.contains(")");
    }

    /**
     * 截取方法名和参数 - 修复版
     */
    public static MethodInfo extractMethod(String formula) {
        if (formula == null || !formula.startsWith("@")) {
            throw new IllegalArgumentException("Invalid formula format: " + formula);
        }

        formula = formula.trim();
       // System.out.println("开始解析公式: " + formula);

        // 找到方法名的结束位置（第一个括号）
        int parenStart = formula.indexOf('(');
        if (parenStart == -1) {
            throw new IllegalArgumentException("No opening parenthesis found: " + formula);
        }

        // 提取方法名
        String methodName = formula.substring(1, parenStart).trim();
   //     System.out.println("方法名: " + methodName);

        // 找到匹配的右括号
        int parenEnd = findMatchingParenthesis(formula, parenStart);
        if (parenEnd == -1) {
            throw new IllegalArgumentException("Unmatched parentheses: " + formula);
        }

        // 提取参数部分
        String paramsStr = formula.substring(parenStart + 1, parenEnd).trim();
     //   System.out.println("参数字符串: '" + paramsStr + "'");

        // 解析参数
        List<String> parameters = parseParametersFixed(paramsStr);

        return new MethodInfo(methodName, parameters);
    }

    /**
     * 找到匹配的右括号
     */
    private static int findMatchingParenthesis(String formula, int startIndex) {
        int level = 1; // 从1开始，因为我们已经有一个左括号
        for (int i = startIndex + 1; i < formula.length(); i++) {
            char c = formula.charAt(i);
            if (c == '(') {
                level++;
            } else if (c == ')') {
                level--;
                if (level == 0) {
                    return i;
                }
            }
        }
        return -1; // 没有找到匹配的右括号
    }

    /**
     * 修复版参数解析
     */
    private static List<String> parseParametersFixed(String paramsStr) {
        List<String> params = new ArrayList<>();
        if (paramsStr == null || paramsStr.trim().isEmpty()) {
            return params;
        }


        int bracketLevel = 0;
        StringBuilder currentParam = new StringBuilder();

        for (int i = 0; i < paramsStr.length(); i++) {
            char c = paramsStr.charAt(i);
            if (c == '(') {
                bracketLevel++;
                currentParam.append(c);
            } else if (c == ')') {
                bracketLevel--;
                currentParam.append(c);
            } else if (c == ',' && bracketLevel == 0) {
                // 只有在最外层括号级别才分割参数
                String param = currentParam.toString().trim();
                if (!param.isEmpty()) {
                    params.add(param);
                }
                currentParam = new StringBuilder();
            } else {
                currentParam.append(c);
            }
        }

        // 添加最后一个参数
        String lastParam = currentParam.toString().trim();
        if (!lastParam.isEmpty()) {
            params.add(lastParam);
        }
        //System.out.println("最终参数列表: " + params);
        return params;
    }
    /**
     * 方法信息类
     */
    public static class MethodInfo {
        private final String methodName;
        private final List<String> parameters;

        public MethodInfo(String methodName, List<String> parameters) {
            this.methodName = methodName;
            this.parameters = parameters;
        }

        public String getMethodName() {
            return methodName;
        }

        public List<String> getParameters() {
            return parameters;
        }

        @Override
        public String toString() {
            return "MethodInfo{" +
                    "methodName='" + methodName + '\'' +
                    ", parameters=" + parameters +
                    '}';
        }
    }
}


/**
 * 字符串操作方法
 */
class StringOperations {

    @Method(name = "helloword", description = "字符串连接")
    public static String helloword() {
        return "hello word";
    }

    @Method(name = "concat", description = "字符串连接")
    public static String concat(List<Object> params) {
        StringBuilder result = new StringBuilder();
        for (Object param : params) {
            result.append(String.valueOf(param));
        }
        return result.toString();
    }

    @Method(name = "upper", description = "转换为大写")
    public static String upper(List<Object> params) {
        validateParams(params, 1, "upper");
        return String.valueOf(params.get(0)).toUpperCase();
    }

    @Method(name = "lower", description = "转换为小写")
    public static String lower(List<Object> params) {
        validateParams(params, 1, "lower");
        return String.valueOf(params.get(0)).toLowerCase();
    }

    private static void validateParams(List<Object> params, int expected, String methodName) {
        if (params.size() != expected) {
            throw new IllegalArgumentException(
                    String.format("Method %s requires %d parameters, but got %d",
                            methodName, expected, params.size()));
        }
    }
}

/**
 * 逻辑运算方法
 */
class LogicalOperations {

    @Method(name = "if", description = "条件判断")
    public static Object ifThenElse(List<Object> params) {
        validateParams(params, 3, "if");
        Boolean condition = toBoolean(params.get(0));
        return condition ? params.get(1) : params.get(2);
    }

    @Method(name = "and", description = "逻辑与")
    public static Boolean and(List<Object> params) {
        for (Object param : params) {
            if (!toBoolean(param)) {
                return false;
            }
        }
        return true;
    }

    @Method(name = "or", description = "逻辑或")
    public static Boolean or(List<Object> params) {
        for (Object param : params) {
            if (toBoolean(param)) {
                return true;
            }
        }
        return false;
    }

    private static Boolean toBoolean(Object obj) {
        if (obj instanceof Boolean) {
            return (Boolean) obj;
        }
        if (obj instanceof String) {
            return Boolean.parseBoolean((String) obj);
        }
        if (obj instanceof Number) {
            return ((Number) obj).doubleValue() != 0;
        }
        return obj != null;
    }

    private static void validateParams(List<Object> params, int expected, String methodName) {
        if (params.size() != expected) {
            throw new IllegalArgumentException(
                    String.format("Method %s requires %d parameters, but got %d",
                            methodName, expected, params.size()));
        }
    }
}

class MathOperations {
    @Method(name = "add", description = "加法运算")
    public static Object add(int a,int b) {
        Number num1 = toNumber(a);
        Number num2 = toNumber(b);

        if (num1 instanceof Double || num2 instanceof Double) {
            return num1.doubleValue() + num2.doubleValue();
        } else if (num1 instanceof Long || num2 instanceof Long) {
            return num1.longValue() + num2.longValue();
        } else {
            return num1.intValue() + num2.intValue();
        }
    }

    @Method(name = "multiply", description = "乘法运算")
    public static Object multiply(int a,int b) {
        Number num1 = toNumber(a);
        Number num2 = toNumber(b);

        if (num1 instanceof Double || num2 instanceof Double) {
            return num1.doubleValue() * num2.doubleValue();
        } else if (num1 instanceof Long || num2 instanceof Long) {
            return num1.longValue() * num2.longValue();
        } else {
            return num1.intValue() * num2.intValue();
        }
    }

    @Method(name = "max", description = "取最大值")
    public static Object max(List<Object> params) {
        validateParams(params, 2, "max");
        Number num1 = toNumber(params.get(0));
        Number num2 = toNumber(params.get(1));

        return Math.max(num1.doubleValue(), num2.doubleValue());
    }

    @Method(name = "min", description = "取最小值")
    public static Object min(List<Object> params) {
        validateParams(params, 2, "min");
        Number num1 = toNumber(params.get(0));
        Number num2 = toNumber(params.get(1));

        return Math.min(num1.doubleValue(), num2.doubleValue());
    }

    private static Number toNumber(Object obj) {
        if (obj instanceof Number) {
            return (Number) obj;
        }
        throw new IllegalArgumentException("Parameter must be a number: " + obj);
    }

    private static void validateParams(List<Object> params, int expected, String methodName) {
        if (params.size() != expected) {
            throw new IllegalArgumentException(
                    String.format("Method %s requires %d parameters, but got %d",
                            methodName, expected, params.size()));
        }
    }
}